package learning.pcfg.model;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class Parser {

	private static enum State { NONE, TERMINALS, PRODUCTIONS };
	
	private List<TerminalProduction> terminals;
	private List<InnerProduction> innerProds;
	private int nl = -1;
	
	public Grammar parse(String file) 
		throws IOException {
		
		terminals = new ArrayList<TerminalProduction>();
		innerProds = new ArrayList<InnerProduction>();
		
		BufferedReader br = new BufferedReader(new InputStreamReader
				(new FileInputStream(file), "utf-8"));
		String line = null;
		State state = State.NONE;
		nl = 0;
		
		while ((line = br.readLine()) != null) {
			// ignore comments
			if (line.startsWith("//")) continue;
			
			if (state.equals(State.NONE)) {
				if (line.startsWith("[TERMINALS]"))
					state = State.TERMINALS;
				else if (line.startsWith("[PRODUCTIONS]"))
					state = State.PRODUCTIONS;
			} 
			else if (state.equals(State.TERMINALS)) {
				if (line.startsWith("[PRODUCTIONS]"))
					state = State.PRODUCTIONS;
				else
					parseTerminals(line);
			}
			else if (state.equals(State.PRODUCTIONS)) {
				if (line.startsWith("[TERMINALS]"))
					state = State.PRODUCTIONS;
				else
					parseInnerProd(line);
			}
			nl++;
		}
		br.close();
		return new Grammar(terminals, innerProds);
	}
	
	private void parseTerminals(String line) {
		String[] ts = line.split(" ");
		for (String t : ts) 
			terminals.add(new TerminalProduction(t.trim()));
	}
	
	private void parseInnerProd(String line) {
		String group = null, lhs = null, rhs = null;
		
		if (line.startsWith("{")) {
			int e = line.indexOf("}");
			if (e < 0) parseError(line);
			group = line.substring(1, e).trim();
			line = line.substring(e+1);
		}
		
		int a = line.indexOf("->");
		if (a < 0) parseError(line);
		lhs = line.substring(0, a).trim();
		rhs = line.substring(0, a + "->".length()).trim();
		
		if (lhs.length() < 1) parseError(line);
		if (rhs.length() < 1) parseError(line);
		
		String[] rhss = rhs.split(" ");
		innerProds.add(new InnerProduction(group, lhs, rhss));
	}
	
	private void parseError(String line) {
		System.out.println("Error parsing line " + nl + ": " + line);
		System.exit(-1);
	}
	
}
